package fun.xstar.handler;

import cn.hutool.json.JSONUtil;
import fun.xstar.exception.BusinessException;
import fun.xstar.model.DeviceInfo;
import fun.xstar.model.DeviceList;
import fun.xstar.model.QueryPage;
import fun.xstar.model.Token;
import fun.xstar.model.YsResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.List;

import static fun.xstar.common.Constant.PARAM_ACCESS_TOKEN;
import static fun.xstar.common.Constant.PARAM_APP_KEY;
import static fun.xstar.common.Constant.PARAM_APP_SECRET;
import static fun.xstar.common.Constant.PARAM_DEVICE_SERIAL;
import static fun.xstar.common.Constant.PARAM_IS_DEFENCE;
import static fun.xstar.common.Constant.PARAM_PAGE_SIZE;
import static fun.xstar.common.Constant.PARAM_PAGE_START;
import static fun.xstar.common.Constant.PARAM_PROTOCOL;
import static fun.xstar.common.Constant.PARAM_QUALITY;
import static fun.xstar.common.Constant.PARAM_VALIDATE_CODE;
import static fun.xstar.enums.LiveStreamProtocolEnum.HLS;
import static fun.xstar.enums.LiveStreamQualityEnum.SP;
import static fun.xstar.enums.YsResultEnum.SUCCESS;

/**
 * @author Afan
 * @version 1.0 2023/11/22
 */
@Slf4j
@Component
public class YsHandler {
    private static final ThreadLocal<Token> TOKEN_CONTEXT = new ThreadLocal<>();

    @Value("${open.ys7.url.token:https://open.ys7.com/api/lapp/token/get}")
    private String tokenUrl;
    @Value("${open.ys7.url.deviceList:https://open.ys7.com/api/lapp/device/list}")
    private String deviceListUrl;
    @Value("${open.ys7.url.deviceInfo:https://open.ys7.com/api/lapp/device/info}")
    private String deviceInfoUrl;
    @Value("${open.ys7.url.deviceAdd:https://open.ys7.com/api/lapp/device/add}")
    private String deviceAddUrl;
    @Value("${open.ys7.url.deviceDelete:https://open.ys7.com/api/lapp/device/delete}")
    private String deviceDeleteUrl;
    @Value("${open.ys7.url.liveAddress:https://open.ys7.com/api/lapp/v2/live/address/get}")
    private String getLiveAddressUrl;
    @Value("${open.ys7.url.setDefence:https://open.ys7.com/api/lapp/device/defence/set}")
    private String setDefenceUrl;
    @Value("${open.ys7.appKey}")
    private String appKey;
    @Value("${open.ys7.appSecret}")
    private String appSecret;
    @Resource
    private RestTemplate restTemplate;

    /**
     * 获取token
     *
     * @return token
     */
    public String getAccessToken() {
        long currentTimeMillis = System.currentTimeMillis();
        Token token = TOKEN_CONTEXT.get();
        if (token != null && token.getExpireTime() > currentTimeMillis) {
            return token.getAccessToken();
        } else {
            TOKEN_CONTEXT.remove();
        }

        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_APP_KEY, appKey);
        requestParams.add(PARAM_APP_SECRET, appSecret);

        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);

        ParameterizedTypeReference<YsResult<Token>> reference = new ParameterizedTypeReference<YsResult<Token>>() {
        };

        YsResult<Token> ysResult = restTemplate.exchange(tokenUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }
        token = ysResult.getData();
        TOKEN_CONTEXT.set(token);
        return token.getAccessToken();
    }

    /**
     * 获取设备列表
     *
     * @param queryPage
     * @return
     */
    public List<DeviceList> queryDeviceList(QueryPage queryPage) {

        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_ACCESS_TOKEN, this.getAccessToken());
        requestParams.add(PARAM_PAGE_START, queryPage.getPageStart());
        requestParams.add(PARAM_PAGE_SIZE, queryPage.getPageSize());
        ParameterizedTypeReference<YsResult<List<DeviceList>>> reference = new ParameterizedTypeReference<YsResult<List<DeviceList>>>() {
        };

        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);
        YsResult<List<DeviceList>> ysResult = restTemplate.exchange(deviceListUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }

        return ysResult.getData();
    }

    /**
     * 根据设备序列号获取设备信息
     *
     * @param deviceSerial
     * @return
     */
    public DeviceInfo queryDeviceInfo(String deviceSerial) {
        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_ACCESS_TOKEN, this.getAccessToken());
        requestParams.add(PARAM_DEVICE_SERIAL, deviceSerial);
        ParameterizedTypeReference<YsResult<DeviceInfo>> reference = new ParameterizedTypeReference<YsResult<DeviceInfo>>() {
        };
        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);
        YsResult<DeviceInfo> ysResult = restTemplate.exchange(deviceInfoUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }
        return JSONUtil.parse(ysResult.getData()).toBean(DeviceInfo.class);
    }

    /**
     * 添加设备
     *
     * @param deviceSerial
     * @param validateCode
     * @return
     */
    public void addDevice(String deviceSerial, String validateCode) {
        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_ACCESS_TOKEN, this.getAccessToken());
        requestParams.add(PARAM_DEVICE_SERIAL, deviceSerial);
        requestParams.add(PARAM_VALIDATE_CODE, validateCode);

        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);
        ParameterizedTypeReference<YsResult> reference = new ParameterizedTypeReference<YsResult>() {
        };

        YsResult ysResult = restTemplate.exchange(deviceAddUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }
    }

    /**
     * 删除设备
     *
     * @param deviceSerial
     */
    public void deleteDevice(String deviceSerial) {
        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_ACCESS_TOKEN, this.getAccessToken());
        requestParams.add(PARAM_DEVICE_SERIAL, deviceSerial);

        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);
        ParameterizedTypeReference<YsResult> reference = new ParameterizedTypeReference<YsResult>() {
        };

        YsResult ysResult = restTemplate.exchange(deviceDeleteUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }
    }

    /**
     * 获取设备hls地址
     *
     * @param deviceSerial
     * @return
     */
    public String getHlsUrl(String deviceSerial) {
        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_ACCESS_TOKEN, this.getAccessToken());
        requestParams.add(PARAM_DEVICE_SERIAL, deviceSerial);
        requestParams.add(PARAM_PROTOCOL, HLS.code);
        requestParams.add(PARAM_QUALITY, SP.code);
        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);
        ParameterizedTypeReference<YsResult<String>> reference = new ParameterizedTypeReference<YsResult<String>>() {
        };

        YsResult<String> ysResult = restTemplate.exchange(getLiveAddressUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }
        return ysResult.getData();
    }

    /**
     * 设备布、撤防
     *
     * @param deviceSerial
     * @param isDefence
     */
    public void setDefence(String deviceSerial, boolean isDefence) {

        LinkedMultiValueMap<String, Object> requestParams = new LinkedMultiValueMap<>();
        requestParams.add(PARAM_ACCESS_TOKEN, this.getAccessToken());
        requestParams.add(PARAM_DEVICE_SERIAL, deviceSerial);
        requestParams.add(PARAM_IS_DEFENCE, isDefence ? 1 : 0);
        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestParams);
        ParameterizedTypeReference<YsResult> reference = new ParameterizedTypeReference<YsResult>() {
        };
        YsResult ysResult = restTemplate.exchange(setDefenceUrl, HttpMethod.POST, httpEntity, reference).getBody();
        if (!StringUtils.equals(ysResult.getCode(), SUCCESS.code)) {
            throw new BusinessException(JSONUtil.toJsonStr(ysResult));
        }
    }
}
